//pragma javascript
//pragma module PlayerLogin
function PlayerLoginMain(sender, arg){
	if (arg.length === 0) {
		let helpStr = ['§7------ PlayerLogin Help ------'];
		for (i = 0; i<CommandList.length; i++){
			helpStr.push("§2/"+CommandList[i][0]+ ":§f " +CommandList[i][1]);
		}
		return sender.sendMessage(helpStr.join("\n"));
	}
	if (arg[0] === "reset") {
		if (!isPlayer(sender)) {
			return sender.sendMessage("Only player!");
		}
		let data = getPlayerData(sender);
		if (data.password === "") {
			return sender.sendMessage(TranslationCore(player.getLoginChainData().getLanguageCode(), 'err.unregister'));
		}
		if (data.newpassword != "") {
			return sender.sendMessage(TranslationCore(player.getLoginChainData().getLanguageCode(), 'err.inRepassword'));
		}
		rePassWordWin(sender.getPlayer());
	}
	if (!sender.isOp()) {
		return sender.sendMessage("Only op.");
	}
	if (arg[0] === "sendmail") {
		if (!arg[1]) {
			return sender.sendMessage(TranslationCore(server.getLanguage().getLang(), "tips.unInputMail"));
		}
		if (!new RegExp(Config.Regex).test(arg[1])) {
			return sender.sendMessage(TranslationCore(player.getLoginChainData().getLanguageCode(), 'err.email'));
		}
		sender.sendMessage("已发送");
		manager.runThread('PlayerLoginSendMail', arg[1], 'RPG - 乱世曙光', '验证码为: test', 'AccountTest', "You");
	} else if (arg[0] === "pass") {
		let player = server.getPlayer(arg[1]);
		if (player === null) {
			return sender.sendMessage("选中的玩家不在线");
		}
		let data = getPlayerData(arg[1], {isName: true});
		if (data === false) {
			return sender.sendMessage("没有 "+arg[1]+" 的数据");
		}
		PlayerLoginSucc(player, data);
	}
}
function loginWin(player){
	player.teleport(server.getLevelByName(Config.midWorld).getSpawnLocation());
	let data = getPlayerData(player);
	let win = window.getCustomWindowBuilder(TranslationCore(player.getLoginChainData().getLanguageCode(), 'win.inputPw.title'));
	win.buildInput(TranslationCore(player.getLoginChainData().getLanguageCode(), 'win.inputPw.pw1'), TranslationCore(player.getLoginChainData().getLanguageCode(), 'win.inputPw.pw2'));
	if (Config.freeVCodeTime != 0 && data.loginvtime + 86400000* Config.freeVCodeTime < new Date().getTime()){
		if (data.loginvcode === 0){
			random = Math.random().toString().substr(5, 6);
			data.loginvcode = random;
			manager.runThread('PlayerLoginSendMail', data.email, 'RPG - 乱世曙光', '验证码为: '+random, 'Account', player);
		}
		win.buildInput(TranslationCore(player.getLoginChainData().getLanguageCode(), 'win.VerificationCode.1'), TranslationCore(player.getLoginChainData().getLanguageCode(), 'win.VerificationCode.2'));
	} else {
		win.buildToggle(TranslationCore(player.getLoginChainData().getLanguageCode(), 'win.forgotPw'), false);
	}
	win.showToPlayer(player, 'loginWinCallback', true);
}
function PlayerLoginSendMail(receivers, subject, mail_msg, sender_name, user_name) {
	let name = isPlayer(user_name) ? user_name.name : user_name;
	//let res = mailapi.send(receivers, subject, mail_msg, sender_name, name);
	let res = manager.callFunction("mail.php::send", receivers, subject, mail_msg, sender_name, name);
	if (res) {
		logger.info(subject + " 邮件发送成功");
	} else {
		logger.info(subject + " 邮件发送失败");
		if (isPlayer(user_name)) {
			user_name.sendMessage("向 "+receivers+" 验证码发送失败");
		}
	}
	let firstName = receivers.split("@")[0];
	if (ServerAPI && !isNaN(firstName)) {
		//ServerAPI.sendMsgToBot(ServerAPI.parseHTML(mail_msg), "sendPrivateMsg", firstName);
	}
}
function loginWinCallback(ent){
	let player = ent.getPlayer();
	if (getPlayerLoginStatus(player.getName()) === 0) {
		return;
	}
	let data = getPlayerData(player);
	let input = window.getEventCustomVar(ent, 0, "input");
	let code = window.getEventCustomVar(ent, 1, "input");
	if (window.getEventCustomVar(ent, 1, "toggle") === "TRUE") {
		data.NoLogin = true;
		savePlayerData(player, data);
		return rePassWordWin(player);
	}
	if (input != undefined && manager.SHA1Encryption(input) != data.password) {
		manager.runThread('PlayerLoginSendMail', 
			data.email, 
			'RPG - 乱世曙光', 
			["# 登录密码错误告警 #", "来自 <a href='https://www.ipip.net/ip/"+player.getAddress()+".html'>"+player.getAddress()+"</a> 的IP正在试图登录您的账户", "若非本人操作请及时更改密码！"].join("<br />"), 
			'Account', 
			player);
		return manager.kickPlayer(player, TranslationCore(player.getLoginChainData().getLanguageCode(), 'kick.errorPassword'));
	}
	if (code != undefined) {
		if (data.loginvcode != code) {
			return manager.kickPlayer(player, TranslationCore(player.getLoginChainData().getLanguageCode(), 'kick.errorVCode'));
		} else {
			data.loginvtime = new Date().getTime();
		}
	}
	delete data.NoLogin;
	if (Config.expand.isSetMode && !Config.midWorld) {// ModeLock插件的兼容
		ModeLockConfig = manager.readFile("./plugins/BlocklyNukkit/ModeLock/Config.yml");
		if (ModeLockConfig != "FILE NOT FOUND") {
			ModeLockConfig = JSON.parse(manager.YAMLtoJSON(ModeLockConfig));
			let to = player.getLevel().getName();
			let mode = ModeLockConfig.mode[to];
			if (mode != undefined && mode != manager.getPlayerGameMode(player) && ModeLockConfig.whitelist.indexOf(player.name) === -1) {
				player.setGamemode(mode);
			}
			if (ModeLockConfig.tips[to]) {
				player.sendMessage(ModeLockConfig.tips[to]);
			}
			if (ModeLockConfig.title[to] && ModeLockConfig.title[to].length > 0) {
				player.sendTitle(ModeLockConfig.title[to][0], ModeLockConfig.title[to][1], ModeLockConfig.title[to][2], ModeLockConfig.title[to][3], ModeLockConfig.title[to][4]);
			}
		}
	}
	data.logintime = new Date().getTime();
	data.ip = player.getAddress();
	data.loginvcode = 0;
	PlayerLoginSucc(player, data);
}
function rePassWordWin(player){//修改密码窗口
	let win = window.getCustomWindowBuilder(TranslationCore(player.getLoginChainData().getLanguageCode(), 'win.rePw.title'));
	win.buildInput(TranslationCore(player.getLoginChainData().getLanguageCode(), 'win.rePw.pw1'), TranslationCore(player.getLoginChainData().getLanguageCode(), 'win.rePw.pw1'));
	win.buildInput(TranslationCore(player.getLoginChainData().getLanguageCode(), 'win.rePw.again.pw1'), TranslationCore(player.getLoginChainData().getLanguageCode(), 'win.rePw.again.pw2'));
	win.showToPlayer(player, 'rePassWordWinCallback', true);
}
function rePassWordWinCallback(ent){//修改密码窗口回调
	let player = ent.getPlayer();
	let data = getPlayerData(player);
	let arr = [];
	for (i = 0; i < 2; i++) {
		let input = window.getEventCustomVar(ent, i, "input");
		if (input && input != "NULL") {
			arr.push(window.getEventCustomVar(ent, i, "input"));
			continue;
		}
		return player.sendMessage(TranslationCore(player.getLoginChainData().getLanguageCode(), 'err.inputNull').replace("%1", i+1));
	}
	if (arr[0] != arr[1]) {
		return player.sendMessage(TranslationCore(player.getLoginChainData().getLanguageCode(), 'err.password'));
	}
	let random = Math.random().toString().substr(5, 6);
	data.vcode = random;
	data.newpassword = manager.SHA1Encryption(arr[0]);
	savePlayerData(player, data);
	
	manager.runThread('PlayerLoginSendMail', 
		data.email, 
		'RPG - 乱世曙光', 
		"更改密码验证码: "+random+"<br />您收到这条邮件是因为有人在阿年服务器 <b>修改</b> 密码时键入了该邮箱，若非本人操作请忽略该邮件。", 
		'Account', 
		player);
	//inputVCodeWin(ent.getPlayer());
}
function regUserWin(player, email){//注册用户窗口
	let win = window.getCustomWindowBuilder(TranslationCore(player.getLoginChainData().getLanguageCode(), 'win.regUser.title'));
	email = email || "";
	if (Config.newUserEmailInput){
		win.buildInput(TranslationCore(player.getLoginChainData().getLanguageCode(), 'win.mail'), Config.newUserEmailInput.defaulttext||"", Config.newUserEmailInput.placeholder||"");
	} else {
		win.buildInput(TranslationCore(player.getLoginChainData().getLanguageCode(), 'win.mail'), "", "");
	}
	win.buildInput(TranslationCore(player.getLoginChainData().getLanguageCode(), 'win.inputPw.pw1'), TranslationCore(player.getLoginChainData().getLanguageCode(), 'win.inputPw.pw2'));
	win.buildInput(TranslationCore(player.getLoginChainData().getLanguageCode(), 'win.regUser.again.pw1'), TranslationCore(player.getLoginChainData().getLanguageCode(), 'win.regUser.again.pw2'));
	win.showToPlayer(player, 'regWinCallback', true);
}
function regWinCallback(event){//注册用户窗口回调
	let player = event.getPlayer();
	let data = getPlayerData(player);
	let arr = [];
	for (i = 0; i < 3; i++) {
		let input = window.getEventCustomVar(event, i, "input");
		if (input) {
			arr.push(window.getEventCustomVar(event, i, "input"));
			continue;
		}
		return player.sendMessage(TranslationCore(player.getLoginChainData().getLanguageCode(), 'err.inputNull').replace("%1", i+1));
	}
	if (arr.length === 3) {
		if (arr[1] != arr[2]) {
			return player.sendMessage(TranslationCore(player.getLoginChainData().getLanguageCode(), 'err.password'));
		}
		if (!new RegExp(Config.Regex).test(arr[0])) {
			return player.sendMessage(TranslationCore(player.getLoginChainData().getLanguageCode(), 'err.email'));
		}
		if (getEmailOfName(arr[0])) {
			return player.sendMessage(TranslationCore(player.getLoginChainData().getLanguageCode(), 'err.mailBeenUsed'));
		}
	}
	let random = Math.random().toString().substr(5, 6);
	data.vcode = random;
	data.password = manager.SHA1Encryption(arr[1]);
	data.email = arr[0];
	savePlayerData(player, data);
	
	manager.runThread('PlayerLoginSendMail', 
		data.email, 
		'RPG - 乱世曙光', 
		"注册验证码: "+random+"<br />您收到这条邮件是因为有人在 <b>注册</b> 阿年服务器时键入了该邮箱，若非本人操作请放心忽略该邮件。", 
		'Account', 
		player);
}
function inputVCodeWin(player){//验证码输入窗口
	let win = window.getCustomWindowBuilder(TranslationCore(player.getLoginChainData().getLanguageCode(), 'win.inputVCode.title'));
	let data = getPlayerData(player);
	win.buildLabel(TranslationCore(player.getLoginChainData().getLanguageCode(), 'win.inputVCode.label').replace("%1", data.email));
	win.buildInput(TranslationCore(player.getLoginChainData().getLanguageCode(), 'win.inputVCode.inputCode1'), TranslationCore(player.getLoginChainData().getLanguageCode(), 'win.inputVCode.inputCode2'));
	if (data.newpassword) {
		win.buildToggle(TranslationCore(player.getLoginChainData().getLanguageCode(), 'win.inputVCode.getup'), false);
	} else {
		win.buildInput(TranslationCore(player.getLoginChainData().getLanguageCode(), 'win.inputVCode.changeMail1'), TranslationCore(player.getLoginChainData().getLanguageCode(), 'win.inputVCode.changeMail2'));
	}
	win.buildToggle(TranslationCore(player.getLoginChainData().getLanguageCode(), 'win.inputVCode.resendVCode'), false);
	win.showToPlayer(player, 'Verification', true);
}
function Verification(ent){//验证码输入窗口回调
	let player = ent.getPlayer();
	let data = getPlayerData(player);
	let input = window.getEventCustomVar(ent, 1, "input");
	let email = window.getEventCustomVar(ent, 2, "input");
	if (window.getEventCustomVar(ent, 3, "toggle") === "TRUE") {
		manager.runThread('PlayerLoginSendMail', 
			data.email, 
			'RPG - 乱世曙光', 
			"验证码: "+data.vcode+"<br />重复发送的验证码，若非本人操作请放心忽略。", 
			'Account', 
			player);
		return;
	}
	if (data.newpassword && window.getEventCustomVar(ent, 2, "toggle") === "TRUE") {//放弃开关
		data.vcode = 0;
		if (data.NoLogin) {
			data.vcode = -2;
			delete data.NoLogin;
		}
		data.newpassword = "";
		savePlayerData(player, data);
		return player.sendMessage(TranslationCore(player.getLoginChainData().getLanguageCode(), 'tips.rePassWordGiveUp'));
	}
	if (email) {
		if (!new RegExp(Config.Regex).test(email) && email != "") {
			return player.sendMessage(TranslationCore(player.getLoginChainData().getLanguageCode(), 'err.email'));
		}
		let random = Math.random().toString().substr(5, 6);
		data.email = email;
		data.vcode = random;
		savePlayerData(player, data);
		
		manager.runThread('PlayerLoginSendMail', 
			data.email, 
			'RPG - 乱世曙光', 
			"注册验证码: "+random+"<br />您收到这条邮件是因为有人在 <b>注册</b> 阿年服务器时键入了该邮箱，若非本人操作请放心忽略该邮件。", 
			'Account', 
			player);
		PlayerLoginCore(ent);
	} else {
		if (input === data.vcode) {
			data.vtime = new Date().getTime();
			if (data.newpassword) {
				data.password = data.newpassword;
				data.newpassword = "";
				player.sendMessage(TranslationCore(player.getLoginChainData().getLanguageCode(), 'tips.rePassWordSucceed'));
			} else {
				setEmailOfName(0, player.name, data.email);
				player.sendMessage(TranslationCore(player.getLoginChainData().getLanguageCode(), 'tips.regSucceed'));
			}
			PlayerLoginSucc(player, data, false);
		} else {
			data.vcode = -1;
			if (data.newpassword && window.getEventCustomVar(ent, 2, "toggle") === "FALSE") {
				data.vcode = -2;
			}
		}
	}
	savePlayerData(player, data);
}
/* 事件处理开始 */
var firstLogin = {};// 首次登陆
function PlayerJoinEvent(event){// 玩家加入游戏事件
	firstLogin[event.getPlayer().getName()] = true;
}
function PlayerQuitEvent(event){// 玩家离开
	let player = event.getPlayer();
	let data = getPlayerData(player);
	if (data === undefined) {
		return;
	}
	// SaveData插件
	let list = database.memoryStorage.getItem("SaveData_OnlineList");
	if (list) {
		list.splice(list.indexOf(player.name), 1);
		database.memoryStorage.setItem("SaveData_OnlineList", list);
		_SaveData.Data2String(player);
	}
	if (data.vcode === 0) {
		data.vcode = -2;
		data.quitime = new Date().getTime();
		ServerAPI.sendMsgToBot(false, "[Lv."+ entity.getPlayerExpLevel(player) +"]"+player.name + " 离开了魔塔");
	}
	if (player.getLevel().name != Config.midWorld) {
		data.position = [player.getLevel().name, player.x, player.y+2, player.z];
	}
	savePlayerData(player, data);
}
function PlayerLoginCore(event){// 核心处理
	let player = event.getPlayer();
	let name = player.name;
	if (firstLogin[name] === undefined) {
		let data = getPlayerData(player);
		let vcode = data.vcode;
		switch(vcode){
			case 0:
				break;
			case -1:
				regUserWin(player);
				break;
			case -2:
				loginWin(player);
				break;
			default:
				if (vcode > 0) {
					inputVCodeWin(player);
				}
		}
		return;
	}
	delete firstLogin[name];
	let t = new Date().getTime();
	let data = getPlayerData(player);
	logger.info(manager.getPlayerDeviceID(player));// b8572ec9cd7a496299f9399b94bdfca5
	logger.info(manager.getPlayerDeviceModal(player));// HUAWEI SEA-AL10
	logger.info(manager.getPlayerDeviceOS(player));// Android
	if (!data.email) {
		player.sendMessage(TranslationCore(player.getLoginChainData().getLanguageCode(), 'tips.newPlayerJoinThink'));
		return PlayerLoginCore(event);
	}
	if (data.vcode > 10) {
		player.sendMessage(TranslationCore(player.getLoginChainData().getLanguageCode(), 'tips.inputVCode'));
		return PlayerLoginCore(event);
	}
	if (data.passLogin) { 
		if (data.passLogin > t) {
			player.sendMessage(TranslationCore(player.getLoginChainData().getLanguageCode(), 'tips.AvoidLogin.succ'));
			data.logintime = t;
			delete data.passLogin;
			savePlayerData(player, data);
			return PlayerLoginSucc(player, data, false);
		}
		delete data.passLogin;
		savePlayerData(player, data);
	}
	if (data.password === "") {
		data.vcode = -1;
		savePlayerData(player, data);
	}
	if (data.vcode === -1 && data.email) {
		player.sendMessage(TranslationCore(player.getLoginChainData().getLanguageCode(), 'tips.errLogout'));
		loginWin(player);
		return;
	}
	if (data.quitime != t) {
		let num = (t - data.quitime)/1000, regReplace = function(str) {
			return str.replace(/%p/ig, '"' + name + '"').replace("%1", Math.floor(num/(60*60*24))).replace("%2", Math.floor(num/(60*60))).replace("%3", Math.floor(num%60));
		}
		if (Config.logintips.tell) player.sendMessage(regReplace(TranslationCore(player.getLoginChainData().getLanguageCode(), 'config.loginTell')));
		if (Config.logintips.say) ent.setJoinMessage(regReplace(TranslationCore(player.getLoginChainData().getLanguageCode(), 'config.loginSay')));
	}
	if (data.Device && manager.getPlayerDeviceID(player) === data.Device.ID) {
	} else if (data.ip != player.getAddress() && "127.0.0.1" != player.getAddress()) {
		player.sendMessage(TranslationCore(player.getLoginChainData().getLanguageCode(), 'tips.loginIPChange'));
		data.vcode = -2;
		savePlayerData(player, data);
		return PlayerLoginCore(event);
	}
	if (Config.freePasswordTime > 0 && data.quitime + Config.freePasswordTime < new Date().getTime()) {
		player.sendMessage(TranslationCore(player.getLoginChainData().getLanguageCode(), 'tips.AvoidLogin.outmoded'));
		data.vcode = -2;
		savePlayerData(player, data);
		return PlayerLoginCore(event);
	}
	player.sendMessage(TranslationCore(player.getLoginChainData().getLanguageCode(), 'tips.autoLogin.succ'));
	data.logintime = t;
	PlayerLoginSucc(player, data, false);
}
manager.customEventListener("cn.nukkit.event.player.PlayerCommandPreprocessEvent", "PlayerLoginCore", "HIGHEST");
manager.customEventListener("cn.nukkit.event.player.PlayerInteractEvent", "PlayerLoginCore", "HIGHEST");
manager.setPrivateCall("PlayerLocallyInitializedEvent", "PlayerLoginCore");
// 初始化
function getPlayerLoginStatus(name){
	if (isPlayer(name)) name = name.getName();
	let data = getPlayerData(name, {isName: true});
	return data === undefined ? false : data.vcode;
}
if (manager.readFile('./plugins/BlocklyNukkit/PlayerLogin/Config.yml') === "FILE NOT FOUND") {
	manager.createConfig(manager.getFile("PlayerLogin", "Config.yml"), 2);
	manager.writeFile("./plugins/BlocklyNukkit/PlayerLogin/Config.yml", manager.JSONtoYAML(JSON.stringify(
		{language:'zh_CN', version:'2020-12-24', Regex: "^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$", freePasswordTime: -1, freeVCodeTime: 0, savePlayerDeviceInfo: true, midWorld: "login", newUserEmailInput: {placeholder: "提示文本", defaulttext: "默认文本"}, logintips: {
			isreplace: true,
			say: false,
			tell: true
		}, sql: {
			switch: false,
			link: "http://127.0.0.1:15850/execsql/",
			host: "",
			port: "3306",
			user: "root",
			password: "",
			database: "",
			table: ""
		}, expand: {
			isSetMode: true,
		}}
	)));
}
if (manager.readFile('./plugins/BlocklyNukkit/PlayerLogin/language/zh_CN.yml') === "FILE NOT FOUND") {
	manager.createConfig(manager.getFile("PlayerLogin/language", "zh_CN.yml"), 2);
	manager.writeFile("./plugins/BlocklyNukkit/PlayerLogin/language/zh_CN.yml", manager.JSONtoYAML(JSON.stringify({
		'config.loginTell': '欢迎来到RPG乱世曙光，距离上次登录 %1天%2小时%3分钟',
		'win.inputVCode.title': '登录 - 安全验证',
		'win.inputVCode.label': "验证码已发送至 %1",
		'win.inputVCode.inputCode1': '如有其它疑问请添加telegram群：https://tg.me/mc_mota§r', 
		'win.inputVCode.inputCode2': '请输入验证码\n§7(注意查看垃圾邮箱)',
		'win.inputVCode.getup': '放弃修改？',
		'win.inputVCode.changeMail1': '修改邮箱？',
		'win.inputVCode.changeMail2': '请输入新邮箱',
		'win.inputVCode.resendVCode': '未收到验证码？(我们将重新发送)',
		'win.inputPw.title': '登录 - 密码输入',
		'win.inputPw.pw1': '密码',
		'win.inputPw.pw2': '请输入密码',
		'win.rePw.title': '登录 - 修改密码',
		'win.rePw.pw1': '新密码',
		'win.rePw.pw2': '请输入新密码',
		'win.rePw.again.pw1': '确认密码',
		'win.rePw.again.pw2': '请重复一次新的登录密码',
		'win.regUser.title': '登录 - 创建账户',
		'win.regUser.again.pw1': '确认密码',
		'win.regUser.again.pw2': '请重复一次登录密码',
		'win.VerificationCode.1': '验证码',
		'win.VerificationCode.2': '请输入验证码',
		'win.forgotPw': '忘记密码？',
		'win.mail': '邮箱',
		'kick.errorPassword': '密码错误',
		'kick.errorVCode': '验证码错误',
		'tips.unInputMail': '未输入邮箱',
		'tips.newPlayerJoinThink': '登陆 >>§a感谢您选择 %1 注册后即刻开始冒险！',
		'tips.inputVCode': '登录 >>§c请先输入验证码',
		'tips.AvoidLogin.succ': '登录 >>§a欢迎回来，您已通过免密登陆',
		'tips.errLogout': '登录 >>§7异常登出，请重新登录',
		'tips.loginIPChange': '登录 >>§7登录IP发生变化',
		'tips.AvoidLogin.outmoded': '登录 >>§7登录授权已过期',
		'tips.loginSucceed': '登录 >>登录成功',
		'tips.regSucceed': '登录 >>注册成功',
		'tips.rePassWordSucceed': '登录 >>密码修改成功',
		'tips.rePassWordGiveUp': '登录 >>已放弃密码修改',
		'tips.autoLogin.succ': '登录 >>§a欢迎回来，我们已为您自动登录',
		'err.inputNull': '§4登录 >>输入框不得留空，在第 %1 项',
		'err.password': '§4登录 >>两次密码必须相同',
		'err.email': '§4登录 >>邮箱有误',
		'err.unregister': '§4该命令必须在已注册状态下执行',
		'err.inRepassword': '§4该命令必须在非改密状态下执行',
		'err.mailBeenUsed': '§4登录 >>该邮箱已被注册'
	})));
}
isExistDir("./plugins/BlocklyNukkit/PlayerLogin/Players", true);
if (manager.readFile("./plugins/BlocklyNukkit/PlayerLogin/PlayerData.json") != "FILE NOT FOUND") {// 旧玩家数据迁移
	logger.info("识别到旧玩家数据开始进行数据迁移...");
	let json = JSON.parse(manager.readFile("./plugins/BlocklyNukkit/PlayerLogin/PlayerData.json"));
	for (i in json) {
		manager.createConfig(manager.getFile("PlayerLogin/Players", i+".yml"), 2);
		manager.writeFile("./plugins/BlocklyNukkit/PlayerLogin/Players/"+i+".yml", manager.JSONtoYAML(JSON.stringify(json[i])));
	}
	let File = Java.type('java.io.File');
	new File('./plugins/BlocklyNukkit/PlayerLogin/PlayerData.json').delete();
	logger.info("旧玩家数据迁移成功。");
}
var PlayerData = {}, Config = JSON.parse(manager.YAMLtoJSON(manager.readFile("./plugins/BlocklyNukkit/PlayerLogin/Config.yml"))),
language = JSON.parse(manager.YAMLtoJSON(manager.readFile("./plugins/BlocklyNukkit/PlayerLogin/language/"+Config.language+".yml"))),
CommandList = [
	['login', '获得帮助'],
	['login reset', '修改密码'],
	['login sendmail <to: Mail>', '测试邮件发送'],
	['login back', '返回上次离开时的坐标点']
];
manager.createCommand(CommandList[0][0], CommandList[0][1], 'PlayerLoginMain');
manager.bStats("PlayerLogin", "2020-12-22", "Mcayear", 7988);
if (Config.midWorld != false) {
	if (isExistDir("./worlds/"+Config.midWorld)) {
		world.loadLevel(Config.midWorld);
	} else {
		world.genLevel(Config.midWorld, 0, "FLAT");
	}
}

// 函数库
function PlayerLoginSucc(player, data, tips) {
	if (tips != false) {
		player.sendMessage(TranslationCore(player.getLoginChainData().getLanguageCode(), 'tips.loginSucceed'));
	}
	if (data.position) {
		world.loadLevel(data.position[0]);
		pos = data.position;
		player.teleport(Java.type("cn.nukkit.level.Position").fromObject(manager.buildvec3(pos[1], pos[2], pos[3]), server.getLevelByName(pos[0])));
	}
	data.logintime = new Date().getTime();
	data.vcode = 0;
	data.Device = {
		OS: manager.getPlayerDeviceOS(player),
		Modal: manager.getPlayerDeviceModal(player),
		ID: manager.getPlayerDeviceID(player)
	};
	EmailOfName[data.email] = player.name;
	savePlayerData(player, data);
	if (_SaveData) {
		_SaveData.String2Data(player);
	}
	if (ServerAPI) {
		ServerAPI.sendMsgToBot(false, "[Lv."+ entity.getPlayerExpLevel(player) +"]"+player.name + " 回到了魔塔大陆");
	}
}
function isExistDir(path, create) {// 判断目录是否存在 return Boolean
	let File = Java.type('java.io.File');
	let dir = new File(path);
	if (dir.exists()) {
		return true;
	} else {
		if (create){
			dir.mkdir();
			return true;
		} else {
			return false;
		}
	}
}
function saveDataToSQL(sql){// 数据库同步
	//more code...
	logger.info(data.code === 0 ? data.res : "请求失败");
}

function UpdateToSQL(sql) {
	//more code...
	//let sql = "UPDATE temp SET qq = 2898415502 WHERE qq = 322";
	manager.httpRequest("GET", Config.sql.link, "sql="+sql);
}
export function getPlayerData(player, obj) {// 获取玩家数据
	if (!obj) {
		obj = {};
	} else if (typeof(obj) === 'string')  {
		obj = JSON.parse(obj);
	}
	let name;
	let time = new Date().getTime();
	let data = {};
	if (obj.isName) {
		if (player.indexOf("@") > -1) {
			name = getEmailOfName(player);
		} else {
			name = player;
		}
	} else {
		name = player.name;
	}
	let content = manager.readFile("./plugins/BlocklyNukkit/PlayerLogin/Players/"+name+".yml");
	if (content === "FILE NOT FOUND") {
		if (!isPlayer(player) || obj.isName) {
			return false;
		}
		data = {
			newpassword: "",
			password: "",
			newemail: "",
			email: "",
			vcode: -1,
			loginvcode: 0,
			loginvtime: 0,
			logintime: time,
			quitime: time,
			position: [player.getLevel().name, Number(player.x.toFixed(1)), Number(player.y.toFixed(1)), Number(player.z.toFixed(1))],
			ip: player.getAddress()
		};
		manager.writeFile("./plugins/BlocklyNukkit/PlayerLogin/Players/"+name+".yml", manager.JSONtoYAML(JSON.stringify(data)));
	} else {
		data = JSON.parse(manager.YAMLtoJSON(content));
		if (Config.sql.switch) {
			let sqldata = JSON.parse(manager.httpRequest("GET", Config.sql.link, "sql=SELECT * FROM user WHERE name =\""+name+"\""))[0];
			if (!sqldata) {
				let sql = "INSERT INTO temp(id, status, qq, name, ip, password, login_time, quit_time, newpassword, newemail, vcode, loginvcode, pos_world, pos_x, pos_y, pos_z) "+
					"VALUES(0,0,?,?,?,?,?,?,?,?,?,?,?,?,?)".replace(/\?/g, "!");
				logger.info(sql);
				manager.httpRequest("GET", Config.sql.link, "sql="+sql+"\&value="+JSON.stringify([data.email.split("@")[0], name, data.ip, data.password, data.logintimem, data.quitime, data.newpassword, data.newemail, data.vcode, data.loginvcode, data.position[0], data.position[1], data.position[2], data.position[3]]));
			}
		}
	}
	data.name = name;
	if (obj.backString) {
		return JSON.stringify(data);
	}
	return data;
}
function savePlayerData(name, data) {
	if (isPlayer(name)) {
		name = name.getName();
	}
	if (Config.sql.switch) {
		UpdateToSQL("UPDATE user SET vcode = "+data.vcode+", login_time = "+data.logintime+", quit_time = "+data.quitime+", password = "+data.password+", newpassword = "+data.newpassword+", pos_world = "+data.position[0]+", pos_x = "+data.position[1]+", pos_y = "+data.position[2]+", pos_z = "+data.position[3]+", ip = "+data.ip+" WHERE name = "+name);
	}
	manager.writeFile("./plugins/BlocklyNukkit/PlayerLogin/Players/"+name+".yml", manager.JSONtoYAML(JSON.stringify(data)));
}

function isPlayer(entity) {
	return entity instanceof Java.type("cn.nukkit.Player");
}


// 建立 email为key name为value的object
var EmailOfName = {};
function updateEmailOfName(){
var File = Java.type('java.io.File'), trdir = new File('./plugins/BlocklyNukkit/PlayerLogin/Players'), trdirl = trdir.listFiles();
for (let i = 0; i < trdirl.length; i++) {
	let f = trdirl[i];
	let temp = JSON.parse(manager.YAMLtoJSON(manager.readFile(new String(f))));
	let name = f.getName().split(".")[0];
	if (temp.email && temp.code > 0 && !temp.newemail && !temp.newpassword) {
		logger.info("清除未验证邮箱的数据: " + name);
		manager.deleteFile(new String(f));
		continue;
	}
	if (!temp.email && !temp.newemail) {
		logger.info("清除无邮箱数据: " + name);
		manager.deleteFile(new String(f));
		continue;
	}
	if (EmailOfName[temp.email]) {
		//logger.info([EmailOfName[temp.email], name]);
		if (EmailOfName[temp.email] === name) {
			continue;
		}
		manager.runThread('PlayerLoginSendMail', 
			temp.email, 
			'RPG - 乱世曙光', 
			"<h2>自动解除邮箱多个账户绑定通知</h2>您收到这条邮件是因为您在 <b>注册</b> 阿年服务器时使用该邮箱绑定了多个账户。<br />我们将立即注销 <b>"+name+"</b> 的注册，因为您已注册 "+EmailOfName[temp.email]+"。<h3># 更改绑定教程</h3>前往QQ群: 595791742，发送<code>/rename &lt;String: 你的新名字&rt;</code><br />例如： <b>/rename Mcayear</b>", 
			'Account', 
			EmailOfName[temp.email]);
		manager.deleteFile(new String(f));
	} else {
		EmailOfName[temp.email] = name;
		if (temp.RenameCount === undefined) {
			temp.RenameCount = 1;
			savePlayerData(name, temp);
		}
	}
}
}
manager.setTimeout(function(){updateEmailOfName()}, 200);
export function getEmailOfName(email) {
	return EmailOfName[email] || "";
}
export function setEmailOfName(oldname, newname, email) {
	if (email) {
		if (manager.readFile("./plugins/BlocklyNukkit/PlayerLogin/Players/"+oldname+".yml") != "FILE NOT FOUND") return JSON.stringify({code: 1, err: oldname+" 文件依旧存在"});
		let obj = JSON.parse(manager.YAMLtoJSON(manager.readFile("./plugins/BlocklyNukkit/PlayerLogin/Players/"+newname+".yml")));
		EmailOfName[obj.email] = newname;
	} else {
		EmailOfName[email] = newname;
	}
	return JSON.stringify({code: 0});
}
export function passPlayerLogin(name, time) {// 设置玩家免密登陆时长
	var data = getPlayerData(name, {isName: true}), time = Number(time);
	if (isNaN(time)) {
		return false;
	}
	if (data === false) {
		return false;
	}
	data.passLogin = new Date().getTime() + time*1000;
	savePlayerData(name, data);
	return true;
}
var mailapi, ServerAPI, _SaveData;
manager.setTimeout(function (){
	mailapi = require("mailapi") || false;
	if (mailapi === false) {
		throw "§ePlayerLogin 缺少必要前置插件“SendMailAPI”,下载链接: §ahttps://www.minebbs.com/resources/mailapi.612/§e";
	} else {
		logger.info("mailapi 加载成功！");
	}
	ServerAPI = require("ServerAPI") || false;
	if (ServerAPI === false) {
		throw "§ePlayerLogin 缺少必要前置插件“ServerAPI”，无法实现QQ消息";
	} else {
		logger.info("ServerAPI 加载成功！");
	}
	_SaveData = require("SaveData") || false;
	if (ServerAPI) {
		logger.info("SaveData 加载成功！");
	}
}, 60);
var LanguageCache = {};
function TranslationCore(lang, strnode) {
	// 判断是否有 strnode
	if (!strnode) return "";
	// 获取 Config.yml 的默认语言
	var defaultLanguage = JSON.parse(manager.YAMLtoJSON(manager.readFile('./plugins/BlocklyNukkit/PlayerLogin/Config.yml'))).language;
	// 如果没有传入 lang 则设为默认语言
	if (!lang) lang = defaultLanguage;
	var languageTable = {};
	// 读取缓存
	if (LanguageCache[lang]) {
		languageTable = LanguageCache[lang];
	} else {
		// 获取指定的语言文件
		var languageFile = manager.readFile('./plugins/BlocklyNukkit/PlayerLogin/language/'+lang+'.yml');
		if (languageFile === "FILE NOT FOUND") {
			logger.info("不存在 "+lang+" 语言，请添加语言文件！");
			lang = defaultLanguage;
			languageFile = manager.readFile('./plugins/BlocklyNukkit/PlayerLogin/language/'+lang+'.yml');
		}
		// 对象
		languageTable = JSON.parse(manager.YAMLtoJSON(languageFile));
		languageFile = null;
	}
	if (languageTable.extends) {
		languageTable = JSON.parse(manager.YAMLtoJSON(manager.readFile('./plugins/BlocklyNukkit/PlayerLogin/language/'+languageTable.extends+'.yml')));
	}
	// 获取字符串节点
	var res = languageTable[strnode];
	if (res) {
		return res;
	} else {
		res = languageTable["none"] || "§4%2 translation node does not exist.";
		return res.replace("%1", lang).replace("%2", strnode);
	}
}